﻿using System;
using System.Collections.Generic;

using Microsoft.StyleCop;

namespace StyleCopContrib.Runner
{
	/// <summary>
	/// Wrapper around the StyleCopConsole class
	/// </summary>
	public sealed class ConsoleRunner : IDisposable
	{
		#region Fields

		private readonly StyleCopConsole _console;
		private readonly IList<string> _outputs;
		private readonly IList<Violation> _violations;

		private bool _isDisposed;

		#endregion

		#region Constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="ConsoleRunner"/> class.
		/// </summary>
		/// <param name="settingsPath">The settings path.</param>
		/// <param name="outputPath">The output path.</param>
		public ConsoleRunner(string settingsPath, string outputPath)
		{
			List<string> addinPaths = new List<string>();
			this._console = new StyleCopConsole(settingsPath, false, outputPath, addinPaths, true);

			this._outputs = new List<string>();
			this._violations = new List<Violation>();
		}

		#endregion

		#region Properties

		/// <summary>
		/// Gets the StyleCop environment.
		/// </summary>
		/// <value>The StyleCop environment.</value>
		public StyleCopEnvironment Environment
		{
			get
			{
				return this._console.Core.Environment;
			}
		}

		#endregion

		#region Methods

		/// <summary>
		/// Analyzes the specified code project.
		/// </summary>
		/// <param name="codeProject">The code project.</param>
		/// <returns>The <see cref="AnalysisResults"/> object of the analyzed <see cref="CodeProject"/> list.</returns>
		public AnalysisResults Analyze(CodeProject codeProject)
		{
			return this.Analyze(new List<CodeProject> { codeProject });
		}

		/// <summary>
		/// Analyzes the specified code projects.
		/// </summary>
		/// <param name="codeProjects">The code projects.</param>
		/// <returns>The <see cref="AnalysisResults"/> object of the analyzed <see cref="CodeProject"/> list.</returns>
		public AnalysisResults Analyze(IList<CodeProject> codeProjects)
		{
			this._console.ViolationEncountered += (sender, args) => this.AddViolation(args.Violation);
			this._console.OutputGenerated += (sender, args) => this.AddOutput(args.Output);

			DateTime start = DateTime.Now;

			this._console.Start(codeProjects, true);

			return new AnalysisResults(codeProjects, this._outputs, this._violations, DateTime.Now.Subtract(start).TotalSeconds);
		}

		private void AddOutput(string output)
		{
			this._outputs.Add(output);
		}

		private void AddViolation(Violation violation)
		{
			this._violations.Add(violation);
		}

		private void Dispose(bool isDisposing)
		{
			if (!this._isDisposed)
			{
				if (isDisposing)
				{
					if (this._console != null)
					{
						this._console.Dispose();
					}
				}

				this._isDisposed = true;
			}
		}

		#endregion

		#region IDisposable

		/// <summary>
		/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
		/// </summary>
		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		#endregion
	}
}